Rzutowanie typów (casty)
Do czego w zasadzie są te casty
Castowanie typów w C++ służy nam do bezpiecznego zmieniania typu. Kiedyś to robiliśmy poprzez nawias:
#include <iostream> using namespace std; int main() { float x = 2.4f; int y = (int)x; cout << y << endl; // 2 }
Tak się robiło w C. W c++ mamy różna casty
Ważne: Żeby użyć któregokolwiek z poniższych castów, musimy zaincludować biblioteke cstdlib
Do czego jest static_cast?
static_cast to podstawowy cast, który powinien być pierwszym, którego powinniśmy próbować użyć. Tak realnie, robi wszystko to, co cast w stylu C (powyżej), a do tego jest sprawdzany przez kompiler, przez co jest bezpieczniejszy.
static_cast użyjemy wtedy, kiedy jesteśmy pewni, że wiemy co robimy.
Przykłady użycia static_cast:
#include <iostream> #include <cstdlib> using namespace std; int main(){ double x = 3.445; int y = static_cast<int>(x); cout << "x: " << x << endl; cout << "y: " << y << endl; }
Do czego jest dynamic_cast?
dynamic_cast używamy głównie przy polimorfizmie i wyłącznie przy wskaźnikach i referencjach obiektów. Najczęściej castujemy typ klasy pochodnej na klasę bazową. Jest to zazwyczaj w pełni bezpieczne, gdyż castujemy typ bardziej specyficzny na typ bardziej generalny.
Przykłady użycia dynamic_cast:
#include <iostream> #include <cstdlib> using namespace std; class A { public: int a, b; A(int _a, int _b) : a(_b), b(_b) {} virtual void writeInfo() { cout << "To jest funkcja z klasy bazowej" << endl; } }; class B : public A { public: int c; B(int _a, int _b, int _c) : A(_a, _b), c(_c) {} void writeInfo() override { cout << "To jest funkcja z klasy pochodnej" << endl; } void wypiszTylkoWPochodnej() { cout << "Ta funkcja jest tylko w klasie pochodnej" << endl; } }; int main() { B *obj1 = new B(1, 2, 3); A *obj2 = dynamic_cast<A *>(obj1); obj1->writeInfo(); obj1->wypiszTylkoWPochodnej(); obj2->writeInfo(); // obj2->wypiszTylkoWPochodnej(); }
Tutaj w powyższym przykładzie mamy dwie klasy:
-
Bazową A, która zawiera jedną metodę wirtualną writeInfo(), która coś wypisuje w konsoli
-
Pochodną B, która publicznie dziedziczy od klasy A, która zawiera jedną dodatkową metodę wypiszTylkoWPochodnej()
W funkcji main(), mamy zastosowany dynamic_cast, który przerzuca nam wskaźnik typu B na wskaźnik typu A. I teraz obiekt obj2 zgubił wszystkie rzeczy, których nie ma w klasie A (np. metodę wypiszTylkoWPochodnej())
Do czego jest const_cast?
const_cast jest rzadko używany i jest jedynym castem, który usunie const z typu.
Przykład użycia:
- Kiedy funkcja przyjmuje referencję na zwykły typ, a my chcemy do niego wrzucić stałą, możemy użyć do tego const_casta
Przykład użycia const_casta:
#include <iostream> using namespace std; void wypiszZeSpacjami(string &str) { for (char ch : str) { cout << ch << " "; } cout << endl; } int main() { const string tekst = "Jakistekstbezspacji"; cout << tekst << endl; // wypiszZeSpacjami(tekst) - BŁĄD wypiszZeSpacjami(const_cast<string &>(tekst)); return 0; }
Do czego jest reinterpret_cast?
reinterpret_cast jest najrzadziej używanym z tych castów i najczęściej nie powinniśmy go stosować. Używa się go, kiedy dokładnie wiemy co robimy i nie chcemy, żeby kompiler nam cokolwiek sprawdzał.
Najczęściej jest on używany przy nisko poziomowej pracy, kiedy operujemy bezpośrednio na pamięci, a także, kiedy rzutujemy wskaźniki między niepowiązanymi typami.
#include <iostream> using namespace std; int main() { int x = 50; char *znak = reinterpret_cast<char *>(&x); cout << *znak << endl; }